import subprocess
import json
import os
import shutil
import winreg
from PySide6.QtWidgets import QListWidget, QDialog, QVBoxLayout, QPushButton, QMessageBox
from utils.handle import get_dir_size


class WinUninstaller:
    """Windows 应用程序卸载管理器类"""
    REGISTRY_PATHS = [
        r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
        r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    ]

    def __init__(self):
        """初始化卸载管理器，获取已安装程序列表"""
        # self.installed_programs = self.get_installed_programs()
        pass

    def get_installed_programs(self):
        """
        获取系统中已安装的程序列表（包含详细信息）
        Returns:
            List[Dict]: 包含程序详细信息的字典列表
        """
        programs = []
        for reg_path in self.REGISTRY_PATHS:
            try:
                with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path) as key:
                    for i in range(winreg.QueryInfoKey(key)[0]):
                        subkey_name = winreg.EnumKey(key, i)
                        with winreg.OpenKey(key, subkey_name) as subkey:
                            try:
                                program_info = {
                                    "name": winreg.QueryValueEx(subkey, "DisplayName")[0],
                                    "uninstall_string": winreg.QueryValueEx(subkey, "UninstallString")[0],
                                    "install_location": self._get_reg_value(subkey, "InstallLocation"),
                                    "install_date": self._parse_install_date(
                                        self._get_reg_value(subkey, "InstallDate")),
                                    "estimated_size": self._get_reg_value(subkey, "EstimatedSize"),
                                    "actual_size": 0  # 需要后续计算
                                }

                                # 计算实际大小
                                if program_info["install_location"] and os.path.exists(
                                        program_info["install_location"]):
                                    program_info["actual_size"] = get_dir_size(
                                        program_info["install_location"]) / 1024 / 1024  # MB

                                # 优先使用实际大小，没有则使用预估大小
                                if program_info["actual_size"] == 0 and program_info["estimated_size"]:
                                    program_info["actual_size"] = int(program_info["estimated_size"]) / 1024  # KB转MB

                                programs.append(program_info)
                            except (FileNotFoundError, OSError):
                                continue
            except FileNotFoundError:
                continue
        return programs

    def _get_reg_value(self, subkey, value_name):
        """安全获取注册表值"""
        try:
            return winreg.QueryValueEx(subkey, value_name)[0]
        except FileNotFoundError:
            return None

    def _parse_install_date(self, date_str):
        """解析安装日期"""
        if date_str and len(date_str) == 8:
            try:
                return f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
            except:
                return "Unknown"
        return "Unknown"

    def uninstall_program(self, program_name):
        if program_name not in self.installed_programs:
            QMessageBox.warning(None, "错误", f"程序 '{program_name}' 未找到。")
            return
        uninstall_string = self.installed_programs[program_name]
        try:
            subprocess.run(uninstall_string, shell=True, check=True)
            QMessageBox.information(None, "成功", f"成功卸载 {program_name}。")
        except subprocess.CalledProcessError as e:
            QMessageBox.critical(None, "错误", f"卸载 {program_name} 失败。错误信息: {e}")

    def deep_clean(self, program_name):
        """
        对指定程序执行深度清理
        
        Args:
            program_name: 要清理的程序名称
            
        Returns:
            bool: 清理是否成功
        """
        if not self.check_registry_for_program(program_name):
            QMessageBox.warning(None, "错误", f"程序 '{program_name}' 未找到。")
            return
        QMessageBox.information(None, "提示", f"正在为 {program_name} 执行深度清理...")
        leftovers = [
            os.path.join("C:\\Program Files", program_name),
            os.path.join("C:\\Program Files (x86)", program_name),
            os.path.join("C:\\Users", os.getenv("USERNAME"), "AppData", "Roaming", program_name),
            os.path.join("C:\\Users", os.getenv("USERNAME"), "AppData", "Local", program_name)
        ]
        for path in leftovers:
            if os.path.exists(path):
                try:
                    shutil.rmtree(path)
                    QMessageBox.information(None, "成功", f"已删除 {path} 处的残留文件")
                except Exception as e:
                    QMessageBox.critical(None, "错误", f"删除 {path} 时出错: {e}")
        QMessageBox.information(None, "完成", f"{program_name} 的深度清理已完成。")

    def check_registry_for_program(self, program_name):

        for reg_path in self.REGISTRY_PATHS:
            try:
                with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path) as key:
                    for i in range(winreg.QueryInfoKey(key)[0]):
                        subkey_name = winreg.EnumKey(key, i)
                        with winreg.OpenKey(key, subkey_name) as subkey:
                            try:
                                display_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                                if display_name == program_name:
                                    return True
                            except (FileNotFoundError, OSError):
                                continue
            except FileNotFoundError:
                continue
        return False
